#ifndef _CIRCLE_UNION_H_
#define _CIRCLE_UNION_H_

#include <vector>
#include <algorithm>
#include <functional>
#include <string>
#include <fstream>

#ifdef WIN32
#include <Windows.h>
#endif
#include <GL/GL.h>

#include <CGAL/centroid.h>
#include <CGAL/Aff_transformation_2.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>

#include "particle_circle.h"
#include "error_info.h"
//#include "error_info.h"

namespace Packing_common
{

	class Circle_union
	{

	public:

		typedef Particle_circle::Point_2	Point_2;
		typedef Particle_circle::Vector_2	Vector_2;

	public:

		template <class ForIter>
		Circle_union(ForIter first, ForIter last) 
		{
			circles.assign(first, last);
			//cent = CGAL::centroid(circles.begin(), circles.end(), CGAL::Dimension_tag<0>());
		}

		Circle_union() {}

		void push_back(const Particle_circle& circle)
		{
			circles.push_back(circle);
			//cent = CGAL::centroid(circles.begin(), circles.end(), CGAL::Dimension_tag<0>());
		}

		void clear() { circles.clear(); }

		const Particle_circle& circle_at(unsigned int index) const { return circles[index]; }
		
		const std::vector<Particle_circle>::const_iterator begin() const { return circles.begin(); }
		const std::vector<Particle_circle>::const_iterator end() const { return circles.end(); }
		void transform(double theta, double tx, double ty);
		void gl_draw(const GLfloat* fill_color) const;

		inline unsigned int size() const { return circles.size(); }

		inline Point_2 centroid() const { return CGAL::centroid(circles.begin(), circles.end(), CGAL::Dimension_tag<2>()); }

	private:
		std::vector<Particle_circle> circles;
		//Point_2 cent; // centroid of the union, temporarily computed by CGAL
	};

	// read from file
	template <class BackInsertIter>
	BackInsertIter read_circle_unions(const std::string& fn, BackInsertIter res)
	{
		std::ifstream fin(fn.c_str());
		unsigned int nb_unions;
		if (!(fin >> nb_unions))
			throw Bad_input("Bad format in the input file.");
		for (unsigned int i = 0; i < nb_unions; i++)
		{
			unsigned int nb_circles;
			if (!(fin >> nb_circles))
				throw Bad_input("Bad format in the input file.");
			std::vector<Particle_circle> aUnion;
			aUnion.reserve(nb_circles);
			for (unsigned int j = 0; j < nb_circles; j++)
			{
				double cx, cy, squared_radius;
				if (!(fin >> cx))
					throw Bad_input("Bad format in the input file.");
				if (!(fin >> cy))
					throw Bad_input("Bad format in the input file.");
				if (!(fin >> squared_radius))
					throw Bad_input("Bad format in the input file.");
				if (squared_radius < 0.0)
					throw Bad_input("Square of radius must be nonnegative!"); 
				aUnion.push_back(Particle_circle(Particle_circle::Point_2(cx, cy), squared_radius));
			}
			*res++ = Circle_union(aUnion.begin(), aUnion.end());
		}
		return res;
	}
}
#endif